use chat_core::{Chat, ChatType};
use serde::{Deserialize, Serialize};

use crate::{AppError, AppState};



#[derive(Debug, Clone, Serialize,Default, Deserialize)]
pub struct CreateChat {
    pub name: Option<String>,
    pub members: Vec<i64>,
    pub public: bool,
}
impl AppState {
    #[allow(dead_code)]
    pub async fn create_chat(&self,input: CreateChat,ws_id: u64) -> Result<Chat,AppError> {
        let len = input.members.len();
        if len < 2 {
            return Err(AppError::CreateChatError("Chat must have at least 2 members".to_string()));
        }
        if len > 8 && input.name.is_none() {
            return Err(AppError::CreateChatError("Group chat have 8 members mut have a name".to_string()));
        }
        let users = self.fetch_chat_users_by_ids(&input.members).await?;
        if users.len() != len {
            return Err(AppError::CreateChatError("Some members not found".to_string()));
        }
        let chat_type = match (&input.name,len) {
            (None,2) => ChatType::Single,
            (None,_) => ChatType::Group,
            (Some(_),_) =>{
                if input.public {
                    ChatType::PublicChannel
                }else{
                    ChatType::PrivateChannel
                    
                }
            }
        };
        let chat = sqlx::query_as(
            r#"
            INSERT INTO chats (name, ws_id, type, members)
            VALUES ($1, $2, $3, $4)
            RETURNING id, name, ws_id, type, members, created_at
            "#,
        ).bind(&input.name) 
        .bind(ws_id as i64)
        .bind(chat_type)
        .bind(&input.members)
        .fetch_one(&self.pool)
        .await?;
        Ok(chat)
    }
    #[allow(dead_code)]
    pub async fn fetch_all(&self,ws_id: u64) -> Result<Vec<Chat>,AppError> {
        let chats = sqlx::query_as(
            r#"
            SELECT id, name, ws_id, type, members, created_at
            FROM chats
            WHERE ws_id = $1
            "#,
        )
        .bind(ws_id as i64)
        .fetch_all(&self.pool)
        .await?;
        Ok(chats)
    }
    #[allow(dead_code)]
    pub async fn get_by_id(&self,id: u64) -> Result<Option<Chat>, AppError> {
        let chat = sqlx::query_as(
            r#"
            SELECT id, name, ws_id, type, members, created_at
            FROM chats
            WHERE id = $1
            "#,
        )
        .bind(id as i64)
        .fetch_optional(&self.pool)
        .await?;
        Ok(chat)
    }
    #[allow(dead_code)]
    pub async fn delete_by_id(&self,id: u64) -> Result<(), AppError> {
        sqlx::query(
            r#"
            DELETE FROM chats
            WHERE id = $1
            "#,
        )
        .bind(id as i64)
        .execute(&self.pool)
        .await?;
        Ok(())
    }
    #[allow(dead_code)]
    pub async fn is_chat_member(&self,chat_id: u64, user_id: u64) -> Result<bool, AppError> {
        let is_member = sqlx::query(
            r#"
            SELECT 1
            FROM chats
            WHERE id = $1 AND $2 = ANY(members)"#
        ).bind(chat_id as i64)
        .bind(user_id as i64)
        .fetch_optional(&self.pool)
        .await?;
        Ok(is_member.is_some())
    }
    #[allow(dead_code)]
    pub async fn update_chat(&self,id: u64, name: String) -> Result<Chat, AppError> {
        let chat = sqlx::query_as(
            r#"
            UPDATE chats
            SET name = $1
            WHERE id = $2
            RETURNING id, name, ws_id, type, members, created_at
            "#,
        )
        .bind(name)
        .bind(id as i64)
        .fetch_one(&self.pool)
        .await?;
        Ok(chat)
    }
}

#[cfg(test)]
mod tests{
    use anyhow::Result;

    use super::*;
    #[tokio::test]
    async fn check_memeber_should_work() -> Result<()> {
        let (_tdb,state) = AppState::new_for_test().await?;
        let is_number = state.is_chat_member(1,1).await.expect("is_chat_member failed");
        assert_eq!(is_number, true, "is_chat_member failed");
        Ok(())
    }
}